home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
Bitmap Libraries 2.0
/
Examples
/
Rotation
/
BitMap.c
next >
Wrap
Text File
|
1996-07-08
|
15KB
|
533 lines
/* File BitMap.c Copyright (C) 1996 by John R. Montbriand. All Rights Reserved. */
/* File BitMap.c
Copyright (C) 1996 by John Montbriand. All Rights Reserved.
Distribute freely in areas where the laws of copyright apply.
Use at your own risk.
Do not distribute modified copies.
These various BitMap libraries are for free!
See the accompanying file BitMap.txt for details.
*/
#include "BitMap.h"
#include <Memory.h>
#include <ToolUtils.h>
#include <OSUtils.h>
#include <FixMath.h>
#include <Math.h>
#pragma segment BitMaps
BitMap* NewBitMap(short width, short height) {
short rowBytes;
long bytes;
BitMap *bits;
rowBytes = ((width + 15) >> 4) << 1;
bytes = sizeof(BitMap) + ((long) rowBytes) * ((long) height);
if ((bits = (BitMap*) NewPtrClear(bytes)) == NULL) return NULL;
bits->baseAddr = ((char*) bits) + sizeof(BitMap);
bits->rowBytes = rowBytes;
bits->bounds.left = bits->bounds.top = 0;
bits->bounds.right = width;
bits->bounds.bottom = height;
return bits;
}
void KillBitMap(BitMap* bits) {
DisposePtr((Ptr) bits);
}
/* SafeHeightNewBitMap is an internal routine for creating bitmaps
appropriately sized for the left and right rotation routines. */
static BitMap* SafeHeightNewBitMap(short width, short height) {
short safeheight;
BitMap* bits;
safeheight = (((height + 15) >> 4) << 1) * 8;
if ((bits = NewBitMap(width, safeheight)) != NULL) bits->bounds.bottom = height;
return bits;
}
/* ShiftLeftWords is an internal routine called to shift bits to the
left after horizontal flip operations and right rotations. Sometimes
this is required as bitmaps are rotated using the memory
storage conventions rather than the coordinate mapping conventions. */
static void ShiftLeftWords(void* p, long words, short nshifts) {
long i, j;
unsigned short* wp;
for (j=0;j<nshifts;j++) for (wp = (unsigned short*) p, i=0; i<words; i++) {
wp[i] <<= 1;
if (i+1 < words && (wp[i+1] & 0x8000) != 0) wp[i] |= 1;
}
}
BitMap* RotateRight(BitMap* bits) {
short sWidth, sHeight;
BitMap *result, *src, *dst;
unsigned char *sp, bit, *dp, *dbyt, sbyt, mask;
register long x, y, i;
sWidth = bits->bounds.right - bits->bounds.left;
sHeight = bits->bounds.bottom - bits->bounds.top;
if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
src = bits;
dst = result;
sp = (unsigned char*) src->baseAddr;
bit = 0x01;
dp = ((unsigned char*) dst->baseAddr) + dst->rowBytes - 1;
for (y = 0; y < src->bounds.bottom; y++) { // for every row...
for (dbyt = dp, x=0; x < src->rowBytes; x++) // scan the row...
for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt += dst->rowBytes)
if (sbyt & mask) *dbyt |= bit;
if (bit == 0x80) { bit = 0x01; dp--; } else bit <<= 1;
}
x = dst->rowBytes*8 - dst->bounds.right;
dp = (unsigned char*) dst->baseAddr;
for (i = 0; i < dst->bounds.bottom; i++, dp += dst->rowBytes)
ShiftLeftWords(dp, dst->rowBytes/2, x);
}
return result;
}
BitMap* RotateLeft(BitMap* bits) {
short sWidth, sHeight;
BitMap *result, *src, *dst;
register long x, y, i;
unsigned char *sp, bit, *dp, *dbyt, sbyt, mask;
sWidth = bits->bounds.right - bits->bounds.left;
sHeight = bits->bounds.bottom - bits->bounds.top;
if ((result = SafeHeightNewBitMap(sHeight, sWidth)) != NULL) {
src = bits;
dst = result;
sp = (unsigned char*) src->baseAddr;
bit = 0x80;
dp = ((unsigned char*) dst->baseAddr) + (dst->rowBytes * (dst->bounds.bottom-1));
for (y = 0; y < src->bounds.bottom; y++) { // for every row...
for (dbyt = dp, x=0; x < src->rowBytes; x++) // scan the row...
for(sbyt = *sp++, mask = 0x80, i=0;i<8;i++, mask >>= 1, dbyt -= dst->rowBytes)
if (sbyt & mask) *dbyt |= bit;
if (bit == 0x01) { bit = 0x80; dp++; } else bit >>= 1;
}
}
return result;
}
BitMap* FlipVertical(BitMap* bits) {
BitMap *result, *src, *dst;
register long v;
unsigned char *sp, *dp;
if ((result = DuplicateBitMap(bits)) != NULL) {
src = bits;
dst = result;
sp = (unsigned char*) src->baseAddr;
dp = ((unsigned char*) dst->baseAddr) + (dst->bounds.bottom-1)*(long)dst->rowBytes;
for (v = 0; v < src->bounds.bottom; v++) {
BlockMoveData(sp, dp, dst->rowBytes);
sp += src->rowBytes;
dp -= dst->rowBytes;
}
return result;
}
return NULL;
}
BitMap* FlipHorizontal(BitMap* bits) {
BitMap *result, *src, *dst;
register long h, v, i;
unsigned char *sp, *dp, *s, *d, mask, bit, sByte;
result = bits;
if ((result = DuplicateBitMap(bits)) != NULL) {
src = bits;
dst = result;
sp = (unsigned char*) src->baseAddr;
dp = (unsigned char*) dst->baseAddr;
for (v = 0; v < src->bounds.bottom; v++) {
for (s = sp + src->rowBytes, d = dp, h = 0; h < src->rowBytes; h++, d++)
for (mask=0x01, bit=0x80, sByte = *--s, *d=0,i=0; i<8; i++, mask<<=1, bit>>=1)
if (sByte & mask) *d |= bit;
sp += src->rowBytes;
ShiftLeftWords(dp, dst->rowBytes / 2, dst->rowBytes*8 - dst->bounds.right);
dp += dst->rowBytes;
}
return result;
}
return NULL;
}
/* There are two implementations of the RotateBitMap routine: one for
the 68000, and another for the PowerPC. Fixed point math is faster
than floating point on the 68000, however floating point is faster
than fixed point on the PowerPC. The method we use maps pixels that
are set in the source bitmap to their appropriate position in the
destination performing the necessary calculations only if the pixel is
equal to 1. I have heard that better image quality can be found by
mapping from the destination to the source, but I was more interested
in speed when I made this. */
#if defined(powerc) || defined(__powerc)
short myround(float x) {
float low, high;
low = floor(x);
high = ceil(x);
if (fabs(low - x) < fabs(high - x))
return (short) low;
else return (short) high;
}
BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
BitMap *result, *src, *dst;
register long h, v, i;
unsigned char *sp, *dp, *s, *d, bit;
float x, y, rad, crad, srad, zx, zy, ccx, ccy;
short xx, yy;
Point pt;
if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
src = bits;
rad = -(0.017453 * angle);
crad = cos(rad);
srad = sin(rad);
ccx = (float) cx;
ccy = (float) cy;
sp = (unsigned char*) src->baseAddr;
for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
for (s = sp, h = 0; h < src->rowBytes; h++, s++)
for (bit=0x80, i=0; i<8; i++, bit>>=1)
if (((*s) & bit) != 0) {
zx = ((float) (h*8+i)) - ccx;
zy =((float) v) - ccy;
xx = myround(zx*crad + zy*srad + ccx);
if (xx >= src->bounds.left && xx < src->bounds.right) {
yy = myround(zy*crad - zx*srad + ccy);
if (yy >= src->bounds.top && yy < src->bounds.bottom)
BitMapSet(result, xx, yy);
}
}
return result;
}
return NULL;
}
#else
BitMap* RotateBitMap(BitMap* bits, short cx, short cy, float angle) {
BitMap *result, *src, *dst;
register long h, v, i;
unsigned char *sp, *dp, *s, *d, bit;
Fixed x, y, rad, crad, srad, zx, zy, ccx, ccy;
short xx, yy;
Point pt;
if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
src = bits;
rad = FixMul(0x00000478, -X2Fix(angle));
crad = FracCos(rad);
srad = FracSin(rad);
ccx = FixRatio(cx, 1);
ccy = FixRatio(cy, 1);
sp = (unsigned char*) src->baseAddr;
for (v = 0; v < src->bounds.bottom; v++, sp += src->rowBytes)
for (s = sp, h = 0; h < src->rowBytes; h++, s++)
for (bit=0x80, i=0; i<8; i++, bit>>=1)
if (((*s) & bit) != 0) {
zx = FixRatio((h*8+i), 1) - ccx;
zy =FixRatio (v, 1) - ccy;
xx = FixRound(FracMul(zx, crad) + FracMul(zy, srad) + ccx);
if (xx >= src->bounds.left && xx < src->bounds.right) {
yy = FixRound(FracMul(zy, crad) - FracMul(zx, srad) + ccy);
if (yy >= src->bounds.top && yy < src->bounds.bottom)
BitMapSet(result, xx, yy);
}
}
return result;
}
return NULL;
}
#endif
BitMap* iRotateBitMap(BitMap* bits, short cx, short cy, short angle) {
return RotateBitMap(bits, cx, cy, (float) angle);
}
BitMap* DuplicateBitMap(BitMap* bits) {
BitMap *result;
long bytes;
result = bits;
result = NewBitMap(bits->bounds.right, bits->bounds.bottom);
if (result != NULL) {
BlockMoveData(bits, result,
sizeof(BitMap) + ((long) result->rowBytes) * ((long) result->bounds.bottom));
result->baseAddr = ((char*) result) + sizeof(BitMap);
return result;
} else return NULL;
}
BitMap* PaintBucketBitMap(BitMap* bits, short h, short v) {
BitMap *result, *src, *dst;
if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
src = bits;
dst = result;
SeedFill(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
dst->bounds.bottom, dst->rowBytes/2, h, v);
}
return result;
}
BitMap* LassoBitMap(BitMap* bits) {
BitMap *result, *src, *dst;
if ((result = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
src = bits;
dst = result;
CalcMask(src->baseAddr, dst->baseAddr, src->rowBytes, dst->rowBytes,
dst->bounds.bottom, dst->rowBytes/2);
}
return result;
}
BitMap* TraceBitMap(BitMap* bits) {
BitMap *the_edges;
if ((the_edges = NewBitMap(bits->bounds.right, bits->bounds.bottom)) != NULL) {
BitMapPort* bmp;
WithBitMap(the_edges, bmp) {
PlotBitMap(bits, -1, -1, srcOr);
PlotBitMap(bits, 1, -1, srcOr);
PlotBitMap(bits, -1, 1, srcOr);
PlotBitMap(bits, 1, 1, srcOr);
PlotBitMap(bits, 0, 0, srcBic);
}
}
return the_edges;
}
/* EqualBitMaps takes into account that the rowbytes in the differing images may be
different and that bits off to the right of the image may contain garbage. */
Boolean EqualBitMaps(BitMap* a, BitMap* b) {
unsigned char *aptr, *bptr, *arover, *brover;
long x, y, bytecount, extrabits, mask;
/* something not there? */
if (a == NULL || b == NULL) return false;
/* different boundary rectangles? */
if (!EqualRect(&a->bounds, &b->bounds)) return false;
/* different image content? */
aptr = (unsigned char*) a->baseAddr;
bptr = (unsigned char*) b->baseAddr;
bytecount = a->bounds.right/8;
extrabits = a->bounds.right % 8;
mask = -(1<< (8 - extrabits));
for (y=0; y< a->bounds.bottom; y++) {
arover = aptr;
brover = bptr;
for (x=0; x<bytecount; x++)
if (*arover++ != *brover++)
return false;
if (extrabits != 0) {
if (((*arover)&mask) != ((*brover)&mask))
return false;
}
aptr += a->rowBytes;
bptr += b->rowBytes;
}
return true;
}
/* note, we set up the portrect, the port's size, the clip region, and the
visible region all so they refer to the drawable area inside of the
bitmap pointer. */
BitMapPort* NewBMP(BitMap* bits) {
BitMapPort* bmp;
Rect r;
if ((bmp = (BitMapPort*) NewPtr(sizeof(BitMapPort))) != NULL) {
r = bits->bounds;
GetPort(&bmp->gpsave);
OpenPort(&bmp->gp);
SetPortBits(bmp->bits = bits);
PortSize(r.right, r.bottom);
RectRgn(bmp->gp.visRgn, &r);
RectRgn(bmp->gp.clipRgn, &r);
}
return bmp;
}
void DisposeBMP(BitMapPort* bmp) {
if (bmp != NULL) {
SetPort(bmp->gpsave);
ClosePort(&bmp->gp);
DisposePtr((Ptr) bmp);
}
}
BitMap* PICTToBitMap(PicHandle pic) {
BitMap *bits;
BitMapPort* bmp;
Rect r;
r = (*pic)->picFrame;
OffsetRect(&r, -r.left, -r.top);
if ((bits = NewBitMap(r.right, r.bottom)) != NULL) {
WithBitMap(bits, bmp)
DrawPicture(pic, &r);
}
return bits;
}
void PlotBitMap(BitMap* bits, short h, short v, short mode) {
GrafPtr port;
Rect src, dst;
dst = src = bits->bounds;
OffsetRect(&dst, h, v);
GetPort(&port);
CopyBits(bits, &port->portBits, &src, &dst, mode, NULL);
}
PicHandle BitMapToPICT(BitMap* bits) {
PicHandle pic;
GrafPtr saved;
GrafPort port;
Rect r;
r = bits->bounds;
GetPort(&saved);
OpenPort(&port);
ClipRect(&r);
pic = OpenPicture(&r);
PlotBitMap(bits, 0, 0, srcCopy);
ClosePicture();
SetPort(saved);
ClosePort(&port);
return pic;
}
BitMap* BitMapAND(BitMap* a, BitMap* b) {
BitMap *aa, *bb, *result = NULL;
register unsigned char *ap, *bp, *rp;
long i, n;
aa = a;
bb = b;
if (EqualRect(&aa->bounds, &bb->bounds))
if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
rp = (unsigned char *) (result)->baseAddr;
ap = (unsigned char *) aa->baseAddr;
bp = (unsigned char *) bb->baseAddr;
n = (aa->rowBytes * aa->bounds.bottom);
for (i=0; i<n; i++) *rp++ = ((*ap++) & (*bp++));
}
return result;
}
BitMap* BitMapOR(BitMap* a, BitMap* b) {
BitMap *aa, *bb, *result = NULL;
register unsigned char *ap, *bp, *rp;
long i, n;
aa = a;
bb = b;
if (EqualRect(&aa->bounds, &bb->bounds))
if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
rp = (unsigned char *) (result)->baseAddr;
ap = (unsigned char *) aa->baseAddr;
bp = (unsigned char *) bb->baseAddr;
n = (aa->rowBytes * aa->bounds.bottom);
for (i=0; i<n; i++) *rp++ = ((*ap++) | (*bp++));
}
return result;
}
BitMap* BitMapXOR(BitMap* a, BitMap* b) {
BitMap *aa, *bb, *result = NULL;
register unsigned char *ap, *bp, *rp;
long i, n;
aa = a;
bb = b;
if (EqualRect(&aa->bounds, &bb->bounds))
if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
rp = (unsigned char *) (result)->baseAddr;
ap = (unsigned char *) aa->baseAddr;
bp = (unsigned char *) bb->baseAddr;
n = (aa->rowBytes * aa->bounds.bottom);
for (i=0; i<n; i++) *rp++ = ((*ap++) ^ (*bp++));
}
return result;
}
BitMap* BitMapNOT(BitMap* a) {
BitMap *aa, *bb, *result = NULL;
register unsigned char *ap, *bp, *rp;
long i, n;
aa = a;
if ((result = NewBitMap(aa->bounds.right, aa->bounds.bottom)) != NULL) {
rp = (unsigned char *) (result)->baseAddr;
ap = (unsigned char *) aa->baseAddr;
n = (aa->rowBytes * aa->bounds.bottom);
for (i=0; i<n; i++) *rp++ = ~(*ap++);
}
return result;
}
Boolean BitMapTest(BitMap* bits, short h, short v) {
unsigned char* cp;
cp = (unsigned char*) (bits);
return BitTst(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
}
void BitMapSet(BitMap* bits, short h, short v) {
unsigned char* cp;
cp = (unsigned char*) (bits);
BitSet(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
}
void BitMapClear(BitMap* bits, short h, short v) {
unsigned char* cp;
cp = (unsigned char*) (bits);
BitClr(cp + (sizeof(BitMap) + (bits->rowBytes * v)), h);
}
Boolean BitMapToggle(BitMap* bits, short h, short v) {
unsigned char* cp;
cp = (unsigned char*) (bits);
cp += (sizeof(BitMap) + (bits->rowBytes * v));
if (BitTst(cp, h)) {
BitClr(cp, h);
return false;
} else {
BitSet(cp, h);
return true;
}
}
BitMap* StringToBitMap(short font, short size, short face, StringPtr s) {
GrafPort port;
GrafPtr saved;
FontInfo info;
BitMap *result = NULL;
GetPort(&saved);
OpenPort(&port);
TextFont(font);
TextSize(size);
TextFace(face);
GetFontInfo(&info);
if ((result = NewBitMap(StringWidth(s), info.ascent + info.descent)) != NULL) {
SetPortBits(result);
PortSize(result->bounds.right, result->bounds.bottom);
RectRgn(port.visRgn, &result->bounds);
RectRgn(port.clipRgn, &result->bounds);
MoveTo(0, info.ascent);
DrawString(s);
}
SetPort(saved);
ClosePort(&port);
return result;
}
/* end File BitMap.c */